#include <iostream>
using namespace std;
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <ctime>
#include <iomanip>
#include <cstring>
#include <netinet/in.h>
#include <pthread.h>
#include <ctype.h>

#define SERVER_PORT 8080

/* 获取当前时间的函数
内联函数：编译器将函数被插入调用位置，被调用时候才会被展开运行 */
inline std::string getCurrentTime()
{
    auto t = std::time(nullptr);
    auto tm = *std::localtime(&t);
    std::ostringstream oss;
    oss << std::put_time(&tm, "%Y-%m-%d %H:%M:%S");
    return oss.str();
}

/* 打印时间的函数 */
inline void log(const std::string &message, const std::string &level = "INFO")
{
    std::cout << "[" << getCurrentTime() << "] [" << level << "] " << message << std::endl;
}

/* 函数指针 */
void *handleClientInfo(void *arg)
{
    /* 线程分离，让系统管理 */
    pthread_detach(pthread_self());

    /* 通信的文件描述符 */
    int connfd = *(int *)arg;

    /* 读取客户端发送的缓冲区 */
    char buffer[256] = {0};
    char sendMsg[256] = {0};
    int readBytes = 0;

    while (1)   //  循环接收信息
    {
        /* 接收信息 */
        readBytes = read(connfd, buffer, sizeof(buffer));
        if (readBytes < 0)
        {
            perror("readBytes < 0");
            break;
        }
        else if (readBytes == 0)
        {
            /* 客户端断开连接 */
            log("客户端连接断开", "WARNING");
            break;
        }
        else
        {
            buffer[readBytes] = '\0'; // 添加字符串结束符
            log("Received message【湿度检测】 : " + std::string(buffer));

            // 发送响应
            char response[] = "Receive Success!\n";
            write(connfd, response, strlen(response));
        }

        /* 发送信息 */
        strncpy(sendMsg, "hello.\n", sizeof(sendMsg) - 1);
        write(connfd, sendMsg, strlen(sendMsg));
        //cout << connfd << endl;
    }

    /* 回收资源 */
    close(connfd);
    /* 线程退出 */
    pthread_exit(NULL);
}

int main()
{
    /* 创建套接字 */
    int sockfd = socket(AF_INET, SOCK_STREAM, 0);   //IPV4地址符， TCP，阻塞的
    if (sockfd == -1)
    {
        perror("socket error");
        _exit(-1);
    }
    //cout << "sockfd: " << sockfd << endl;

    /* 设置端口复用，即使端口被其他线程占用也可以使用 */
    int optVal = 1;
    int ret = setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optVal, sizeof(optVal));
    if (ret != 0)
    {
        perror("setsockopt error");
        _exit(-1);
    }

    /* 将文件描述符和本地的IP与端口进行绑定 */
    struct sockaddr_in localAddress;
    memset(&localAddress, 0, sizeof(localAddress));
    /* 地址族 */
    localAddress.sin_family = AF_INET;
    /* 本地地址小端字节序，转换成网络大端字节序 */
    localAddress.sin_port = htons(SERVER_PORT);
    localAddress.sin_addr.s_addr = htonl(INADDR_ANY); /* 具体的ip地址 允许服务器接收来自任何IP地址的连接请求 */
    /* 绑定 */
    ret = bind(sockfd, reinterpret_cast<const sockaddr *>(&localAddress), sizeof(localAddress));
    if (ret != 0)
    {
        perror("bind error");
        _exit(-1);
    }

    /* 给监听的套接字设置监听 */
    ret = listen(sockfd, 0);    //设置为0，不允许排队连接，当已连接又有新的请求时，将会拒绝请求；
    if (ret != 0)
    {
        perror("listen error!");
        _exit(-1);
    }
    cout << "server listen ... " << endl;

    int connfd = 0;
    while (1)
    {
        /* 每接受新的客户端连接 - 解除阻塞 */
        /* connfd 连接描述符， 每连接一个客户端，就会生成一个connfd */
        connfd = accept(sockfd, NULL, NULL);        //NULL表示不需要获取有关客户端的地址信息
        if (connfd == -1)
        {
            perror("accept error");
            _exit(-1);
        }
        cout << "与客户端建立连接, connfd: " << connfd << endl;

        /* 程序达到这个地方：就需要单独开辟线程去处理用户的请求 */
        /* 创建一个新的线程 */
        pthread_t tid = 0;
        ret = pthread_create(&tid, NULL, handleClientInfo, (void *)&connfd);
        if (ret != 0)
        {
            perror("thread create error");
            _exit(-1);
        }

        /* 休眠 5s, 给足等待线程创建的时间， */
        sleep(5);
    }

    /* 释放资源 */
    close(connfd);
    /* 关闭文件描述符 */
    close(sockfd);

    cout << "server exited... ByeBye!" << endl;
}